﻿#region Copyright
//       Copyright (c) 2009 - Antoine Jaussoin - http://www.jaussoin.com/blog/
// 
//        This program is free software: you can redistribute it and/or modify
//        it under the terms of the GNU General Public License as published by
//        the Free Software Foundation, either version 3 of the License, or
//        (at your option) any later version.
// 
//        This program is distributed in the hope that it will be useful,
//        but WITHOUT ANY WARRANTY; without even the implied warranty of
//        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//        GNU General Public License for more details.
// 
//        You should have received a copy of the GNU General Public License
//        along with this program.  If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using FT.Architecture.Entities;
using FT.Architecture.Example.Core.Entities.Humans;

namespace FT.Architecture.Example.Core.Entities.Subscriptions
{
    /// <summary>
    /// Represents a subscription (TV, etc.). This is a good example of 
    /// a mapping on a crappy database schema with a composite key
    /// </summary>
    public class Subscription : GenericEntity<SubscriptionId>
    {
        private DateTime subscribedOn;
        private DateTime finishOn;
        private decimal  monthlyPrice;
        
        /// <summary>
        /// Constructor
        /// </summary>
        public Subscription()
        {
            id = new SubscriptionId();
        }

        /// <summary>
        /// Date when this subscription was subscribed on
        /// </summary>
        public virtual DateTime SubscribedOn
        {
            get { return subscribedOn; }
            set { subscribedOn = value; }
        }

        /// <summary>
        /// Finished On
        /// </summary>
        public virtual DateTime FinishOn
        {
            get { return finishOn; }
            set { finishOn = value; }
        }

        /// <summary>
        /// Monthly price
        /// </summary>
        public virtual decimal MonthlyPrice
        {
            get { return monthlyPrice; }
            set { monthlyPrice = value; }
        }

        /// <summary>
        /// Human
        /// </summary>
        public virtual IHuman Human
        {
            get { return id.Human; }
            set { id.Human = value; }
        }

        /// <summary>
        /// Type
        /// </summary>
        public virtual SubscriptionType Type
        {
            get { return id.Type; }
            set { id.Type = value; }
        }
    }

    /// <summary>
    /// Composite identifier for a subscription.
    /// As you can see, it's very easy to map whatever you want, an entity or a simple field
    /// </summary>
    [Serializable]
    public class SubscriptionId
    {
        private IHuman human;
        private SubscriptionType type;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="human"></param>
        /// <param name="type"></param>
        public SubscriptionId(IHuman human, SubscriptionType type)
        {
            this.human = human;
            this.type = type;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public SubscriptionId()
        {

        }

        /// <summary>
        /// Human as part of the ID
        /// </summary>
        public IHuman Human
        {
            get { return human; }
            set { human = value; }
        }

        /// <summary>
        /// Type as part of the ID
        /// </summary>
        public SubscriptionType Type
        {
            get { return type; }
            set { type = value; }
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// <see langword="true"/> if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, <see langword="false"/>.
        /// </returns>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>. </param><exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is <see langword="null"/>.</exception><filterpriority>2</filterpriority>
        public override bool Equals(object obj)
        {
            if (obj is SubscriptionId)
            {
                var o = (SubscriptionId)obj;
                return o.Human.Equals(Human) && o.Type.Equals(Type);
            }

            return false;
        }

        /// <summary>
        /// Serves as a hash function for a particular type. 
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public override int GetHashCode()
        {
            return (Human.GetHashCode() + "#" + Type.GetHashCode()).GetHashCode();
        }
    }

    /// <summary>
    /// Represents the different types of subscription
    /// </summary>
    public enum SubscriptionType
    {
        Television,
        Magazine,
        Internet,
        Insurance,
        Rent,
        Telephone,
        Water,
        Electricity,
        Gas
    }
}
